package util.mib;

import annotation.ShowInfo;
import model.MibNode;
import util.common.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.regex.Pattern;

public class MibFormatUtils {
    public static final Pattern ManySpaceRegex = Pattern.compile(" {2,}");
    public static final Pattern ManyWhiteSpaceRegex = Pattern.compile("[\\s\\r\\n]+");
    public static final Pattern OidSyntaxRegex = Pattern.compile("(\\.\\d+)+");

    /**
     * 把多个空格转换成一个空格。
     * @param str
     * @return
     */
    public static String removeSuperfluousSpace(String str) {
        return str.replaceAll(ManySpaceRegex.toString(), " ");
    }

    /**
     * 把多个空白字符转换成一个空格。
     * @param str
     * @return
     */
    public static String RemoveSuperfluousWhiteChar(String str) {
        return str.replaceAll(ManyWhiteSpaceRegex.toString(), " ");
    }

    /**
     * 合并只有一个子节点到父节点上，且该父节点的值必须为空。
     * @param trees
     */
    public static void mergeNodeWithOneChild(List<MibNode> trees) {
        doMergeNodeWithOneChild(trees, false, false);
    }

    /**
     * 合并只有一个子节点到父节点上，且该父节点的值必须为空。
     * @param trees
     * @param mergeRoot 若根节点跟下一个节点能够合并，是否合并，默认为false。设为true有可能导致根节点变化
     */
    public static void mergeNodeWithOneChild(List<MibNode> trees, boolean mergeRoot) {
        doMergeNodeWithOneChild(trees, false, mergeRoot);
    }

    // 递归合并节点核心逻辑
    private static void doMergeNodeWithOneChild(List<MibNode> trees, boolean mergeRoot, boolean isRoot) {
        for (MibNode tree : trees) {
            if (tree.children.size() == 0){  // 没有子树，跳过
                continue;
            }else if (tree.children.size() == 1 && !tree.isTable && !tree.isTableObject) {
                MibNode child = tree.children.get(0);
                if (
                    ((StringUtils.isNullOrWhiteSpace(child.name) && StringUtils.isNullOrWhiteSpace(tree.name)) // 父子节点名字都为空
                            || child.name.startsWith(tree.name + "."))  // 子节点名字有后缀
                            && StringUtils.isNullOrWhiteSpace(tree.value)//  当前节点没有值
                            && ((!mergeRoot && !isRoot) || mergeRoot) // 是否合并根节点
                ) { // 剪枝
                    tree.name = child.name;
                    tree.value = child.value;
                    tree.oid = child.oid;
                    tree.children = child.children;
                    List<MibNode> tempList = new ArrayList<>(1);
                    tempList.add(tree);
                    doMergeNodeWithOneChild(tempList, mergeRoot, isRoot); // 递归当前节点
                } else {
                    doMergeNodeWithOneChild(tree.children, mergeRoot, isRoot); // 递归子节点
                }
            } else {
                doMergeNodeWithOneChild(tree.children, mergeRoot, false);
            } // 递归
        }
    }

    /**
     * 剪枝，仅保留指定oid集合里包含的子节点及其对应的父节点
     * @param forest
     * @param oids
     * @return
     */
    public static List<MibNode> PruneMibTreeNotContainOids(List<MibNode> forest, HashSet<String> oids) {
        List<MibNode> pruneForest = new ArrayList<>();
        for (MibNode tree : forest) {
            if (doPruneTree(tree, oids)) {
                pruneForest.add(tree);
            }
        }

        return pruneForest;
    }

    // 递归
    private static boolean doPruneTree(MibNode node, HashSet<String> oids) {
        if (node.children.size() == 0) {
            return oids.contains(node.oid);
        }

        boolean childrenContain = false;
        int[] NotContainChildrenIndex = new int[node.children.size()];
        for (int i = node.children.size() - 1; i >= 0; i--) {
            if (doPruneTree(node.children.get(i), oids)) {
                childrenContain = true;
            } else {
                NotContainChildrenIndex[i] = 1;
            }
        }

        if (childrenContain){ // 有子项包含
            for (int i = NotContainChildrenIndex.length - 1; i >= 0; i--){ // 剪枝
                if (NotContainChildrenIndex[i] > 0) {
                    node.children.remove(i);
                }
            }
            return true;
        }else{  // 没有子项包含
            node.children = new LinkedList<>();
            return doPruneTree(node, oids);
        }
    }

    /**
     * 对树进行排序
     * @param forest
     * @return
     */
    public static List<MibNode> sortMibTree(List<MibNode> forest) {
        if (forest == null || forest.size() == 0) {
            return forest;
        }
        forest.sort((o1, o2) -> MibFormatUtils.CompareMibNode(o1, o2));
        for (MibNode tree : forest){
            sortMibTree(tree.children);
        }
        return forest;
    }

    /**
     * 节点排列方法
     * @param x
     * @param y
     * @return
     */
    public static int CompareMibNode(MibNode x, MibNode y) {
        int r = x.level - y.level;
        if (r != 0) {
            return r;
        }
        Integer[] a = StringUtils.splitIntsString(x.oid, "\\.");
        Integer[] b = StringUtils.splitIntsString(y.oid, "\\.");
        for (int i = 0; i < x.level && r == 0; i++) {
            r = a[i].compareTo(b[i]);
        }

        return r;
    }

    /**
     * 把带有@ShowInfo注解的属性编写入builder
     * @param builder
     */
    public static void appendInfoField(StringBuilder builder, Object object) {
        Class clazz = object.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields){
            try {
                Annotation annotation = field.getDeclaredAnnotation(ShowInfo.class);
                if (annotation == null)
                    continue;
                // 判断值是否为空
                String value = null;
                Object valueObject = field.get(object);
                if (valueObject == null){
                    continue;
                }
                if (valueObject instanceof List){ // list类型
                    List list = (List)valueObject;
                    if (list.size() == 0)
                        continue;
                    String name = (String) ShowInfo.class.getDeclaredMethod("name").invoke(annotation);
                    if (name.equals(""))
                        name = field.getName();
                    builder.append(String.format("%s (List)[\n", name));
                    for (Object o : list){
                        String str = o.toString().replaceAll("\\n", "\n--\t");
                        builder.append("--\t").append(str);
                        builder.append("\n");
                    }
                    builder.append("]\n");
                }else if (valueObject instanceof Map){
                    Map map = (Map)valueObject;
                    for (Object o : map.entrySet()){
                        // todo map的格式化
                    }
                }else{
                    value = valueObject.toString();
                    if (value.equals(""))
                        continue;
                    String name = (String)ShowInfo.class.getDeclaredMethod("name").invoke(annotation);
                    if (name == null || name.equals("")){
                        builder.append(String.format("%s: %s\n", field.getName(), value));
                    }else{
                        builder.append(String.format("%s: %s\n", name, value));
                    }
                }
            } catch (IllegalAccessException e) {
                continue;
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取格式化的MibNode信息
     * @param node
     * @return
     */
    public static String getFormatNodeInfo(MibNode node){
        StringBuilder builder = new StringBuilder();
        if (node.moduleName != null && !node.moduleName.trim().equals("")) {
            builder.append(String.format("库：%s\n", node.moduleName));
        }
        MibFormatUtils.appendInfoField(builder, node); // 把有showInfo注解的字段追加进来。
        if (node.description != null && !node.description.trim().equals("")) {
            node.description = node.description.replaceAll("\\t{2,}", "\t");
            builder.append(String.format("描述：%s", node.description));
        }
        return builder.length() > 0 ? builder.toString() : "暂无关于该OID的描述。";
    }
}
